package wsem.services;

import java.io.IOException;
import java.net.URL;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Vector;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.xml.sax.SAXException;

import sparqlclient.SparqlClientExample;
import wsem.model.Document;
import wsem.model.IndexJDBC;
import wsem.model.QueriesJDBC;
import wsem.model.Qrel;
import wsem.model.Query;
import wsem.model.SparqlQuery;
import wsem.parser.ParserXML;
import wsem.parser.QrelParser;
import wsem.parser.QueryParser;
import wsem.result.QueryResult;
import wsem.result.ResultSearch;
import wsem.utils.SparQLUtils;
import wsem.utils.SparqlClient;
import wsem.utils.StopList;
import wsem.utils.XMLUtils;

public class ServiceWSEMImpl implements IServicesWsem {

	public enum EtatIndexage {

		INDEX_BAD, INDEX_OK,

	}

	private StopList spList;

	private EtatIndexage etat;

	private IndexJDBC indexationBD;

	@Override
	public void execEvaluator(int precision) throws SQLException {

		

		startStopList();

		QueriesJDBC searchInIndexMot = new QueriesJDBC();
		

		

		

		LinkedHashMap<String, LinkedList<ResultSearch>> mapResultat = new LinkedHashMap<String, LinkedList<ResultSearch>>();
		LinkedHashMap<String, LinkedList<ResultSearch>> mapAllResultat = new LinkedHashMap<String, LinkedList<ResultSearch>>();
		LinkedHashMap<String, Query> queries = null;

		HashMap<String, Qrel> mapSelectedDoc = null;

//		double nbDocPertinentSelected = 0;
//		double nbTotalDocPertinent = 0;
//		double nbDocSelected = 0;

		LinkedHashMap<QueryResult, String> mapResultQuery = new LinkedHashMap<QueryResult, String>();

		mapSelectedDoc = new HashMap<String, Qrel>();

		// recuperation les 11 requetes

		// Ouverture du qrel
		QrelParser parserQrel = new QrelParser();
		// Recuperation des requetes du fichier xml

		QueryParser queryParse = new QueryParser();
		
		int nbDocSelectedFromPreci = 0;
		
		int compteurPrec = 0;

		try {
			// on parse le fichier
			queryParse.parse();
			// recuperer les 11 requetes (avec l'identifiant)
			queries = queryParse.getQueries();

			// chercher les qrels correspondant � l'identifiant

			for (Entry<String, Query> entryQuery : queries.entrySet()) {

				String nameDocFromQueries = entryQuery.getKey();

				Query queryCurrent = entryQuery.getValue();

				// r�cup�ration de tous les elements
				Vector<Qrel> listeAllElement = parserQrel
						.parseQrel(queryCurrent.getIdQuery());

				for (Qrel qrelSearch : listeAllElement) {

					// On cherche le qrel correspondant � l'identifiant de la
					// queries parser
					

					if (StringUtils.equalsIgnoreCase(qrelSearch.getIdQrel(),
							queryCurrent.getIdQuery())) {

						mapSelectedDoc.put(qrelSearch.getNomDocument(),
								qrelSearch);
						
						if (qrelSearch.isPertinent()) {

							QueryResult qRes = new QueryResult(
								qrelSearch.getNomDocument(),
								qrelSearch.getxPath(),qrelSearch.isPertinent());
							// On stocke les requetes de resultat dans une hashMap

							mapResultQuery.put(qRes, queryCurrent.getQueryValue());
							
							
							
						}

					}

				}
				
			}
			
			for (Entry<QueryResult, String> entryQueryTest : mapResultQuery
					.entrySet()) {

				
				if (compteurPrec < precision) {
					QueryResult qr = entryQueryTest.getKey();
					String qrReq = entryQueryTest.getValue();
					
					String[] termeToTerm = qrReq.split("\\s");
					LinkedList<ResultSearch> listResult = null;
					boolean isPertinent = true;
					for (int i = 0; i < termeToTerm.length && isPertinent; i++) {
				
						if (StringUtils.isNotBlank(XMLUtils.lematiser(spList,
								termeToTerm[i]))) {
							listResult = searchInIndexMot
									.findDocumentIfExistTerm(XMLUtils
											.lematiser(spList, termeToTerm[i]),
											qr.getXpath(), qr.getNomDoc());
							// si liste result null c'est que les noeud du doc
							// ne satisfait pas la requete
							if (listResult == null && listResult.size() == 0) {
								isPertinent = false;
								
							}
							

						}

					}
					
					if (listResult != null && listResult.size() > 0 && isPertinent) {
						mapResultat.put(qr.getNomDoc(), listResult);
							
					}
					//map repertoriant tous les resultats (pertinent ou non pertinent) de chaque document de l'echantillon
					//Un document est pertinent si il existe au moins un r�sultats valide d'un noeud du document (par rapport � la requete)
					mapAllResultat.put(qr.getNomDoc(), listResult);
					compteurPrec = mapAllResultat.size();
				}
				
				
			}

			
			
			
			float rappel = (float) mapResultat.size() / mapSelectedDoc.size();
			double rappelPourcentage = rappel * 100;

			DecimalFormat df = new DecimalFormat("###,##");

			float preci = (float) mapResultat.size() / precision;
			
			System.out.println(preci);
			
			double preciPourcentage = preci * 100;

			System.out.println("NOMBRE TOTAL DE DOC PERTINENT "
					+ mapSelectedDoc.size());
			System.out.println("Precision document " + precision);
			System.out.println("NOMBRE DE DOC PERTINENT SELECTIONNER "
					+ 66);

			System.out
					.println("######################################## Evaluation de performance ############################");
			System.out.println("-------------------------RAPPEL "
					+ df.format(rappelPourcentage) + " %");
			System.out.println("-------------------------PRECISION "
					+ df.format(preciPourcentage) + " %");
			System.out
					.println("###############################################################################################");

		} catch (Exception e) {

			e.printStackTrace();
		}

	}



	@Override
	public void indexAllData(HashMap<String, String> pDocumentList,
			List<Document> collectionDoc) throws SQLException, SAXException,
			IOException {

		System.out.println("PRET");
		etat = EtatIndexage.INDEX_OK;

		// Instanciation du dao
		indexationBD = new IndexJDBC();

		// Connexion a la base

		indexationBD.Connection("jdbc:mysql://localhost/ws_db", "root", "");

		// Suppression de tous les enregistrements des tables

		indexationBD.deletebdd();

		// Insertion des documents d'abord

		indexationBD.ajouterDocument(collectionDoc);

		int compteur = 0;
		for (Entry<String, String> entry : pDocumentList.entrySet()) {
			compteur++;
			
			String path = entry.getKey();
			String nameDoc = entry.getValue();
			System.out.println(nameDoc);
			Document docCurrentUsed = new Document(nameDoc);
			docCurrentUsed.setIdDoc(compteur);

			ParserXML parserCollection = new ParserXML(path, docCurrentUsed,
					indexationBD);

			// etat = parserCollection.isParseIsOk() ? EtatIndexage.INDEX_OK
			// : EtatIndexage.INDEX_BAD;
		}
		

		String stateIndexageMsg = verifyStateIndexage(etat);

		// A afficher pour la futur ihm
		System.err.println("Message state for index collection "
				+ stateIndexageMsg);

	}

	private String verifyStateIndexage(EtatIndexage etat2) {
		String stateIndexageMsg = "";

		switch (etat) {
		case INDEX_BAD:
			stateIndexageMsg = "bad indexed";
			break;

		case INDEX_OK:
			stateIndexageMsg = "All collection are indexed ";
			break;

		default:
			break;
		}

		return stateIndexageMsg;
	}

	private void startStopList() {
		System.out.println("Debut de l'analyse du document");
		// on demarre notre stopList ici
		try {

			URL input = getClass().getResource("/wsem/resources/stopliste.txt");

			spList = new StopList(input.getPath());

		} catch (IOException e) {

			e.printStackTrace();
		}

	}

	@Override
	public void searchExpressionPertinent(String expression) {
		HashMap<String, Float> scoreMap = new HashMap<String, Float>();
		LinkedList<ResultSearch> listResultat = null;
		
		startStopList();
		System.err.println("[expression => "+expression+"]");
		//initialisation du client
		SparqlQuery sparqlQuery = new SparqlQuery();
		

		//Appel methode pour trouver les synonymes
		List<String> synonymeFound = sparqlQuery.getSynonyme(expression);
		//Appel methode pour trouver tous les fils
		List<String> childFound = sparqlQuery.getFils(expression);
		QueriesJDBC searchInIndexMot = new QueriesJDBC();
		//basic
		String[] expFromDoc = expression.split("\\s");
		
		
		
		

	
		//si des synonymes existe
		if(synonymeFound != null){
			//pour chaque synonyme, on recherche les documents pertinents (Reflechir au poid a donnee)
			for(String syn : synonymeFound){
				
				String[] termeFromDoc = syn.split("\\s");
				getScoreElement(termeFromDoc, searchInIndexMot,scoreMap,2);
			}
		}
		if(childFound != null){
			//pour chaque fils, on recherche les documents pertinents (Reflechir au poid a donner
			for(String child : childFound){
				
				String[] termeFromDoc = child.split("\\s");
				getScoreElement(termeFromDoc, searchInIndexMot,scoreMap,3);
			}
		}
		
		
		getScoreElement(expFromDoc, searchInIndexMot, scoreMap, 1);	
		
		//une fois que les synonymes sont trouv� (dans un tableau)
		//en fonction de l'expression
		Double max = 0.0;
		String docSelected = "";
		Float score = null ;
		// Une fois le score calculer, recup�rer le docuement ayant le score le plus elever
		for (Entry<String, Float> scoreSet : scoreMap.entrySet()) {
			String nameDoc = scoreSet.getKey();
			score = scoreSet.getValue();
			if(score > 0 ){

				docSelected = "nom du document le plus pertinent => " + nameDoc + " le score " + score;
				System.out.println("###############################################");
				System.out.println("document le plus pertinent : "+docSelected);
				System.out.println("###############################################");
			}
			
			
		}
		if(score == null){
				System.out.println("Aucun document trouvé pour l'expression recherché");
		
		}
	}



	private void getScoreElement(String[] termeFromDoc, QueriesJDBC searchInIndexMot,HashMap<String, Float> scoreMap, int poid) {
		
		LinkedList<ResultSearch> listResultat;
		LinkedHashMap<String, Query> queries = null;

		HashMap<String, Qrel> mapSelectedDoc = null;

		
		LinkedHashMap<String, QueryResult> mapResultQuery = new LinkedHashMap<String, QueryResult>();
		
		mapSelectedDoc = new HashMap<String, Qrel>();
		

		// recuperer les 11 requetes
		// Ouverture du qrel
		QrelParser qrelReader = new QrelParser();
		
		// Recuperation des requetes du fichier xml
		QueryParser queryParse = new QueryParser();

		try {
			// on parse le fichier
			queryParse.parse();
		// recuperer les 11 requetes (avec l'identifiant)
		queries = queryParse.getQueries();
		
			// chercher les qrels correspondant � l'identifiant
			for (Entry<String, Query> entryQuery : queries.entrySet()) {

				String nameDocFromQueries = entryQuery.getKey();
				Query queryCurrent = entryQuery.getValue();
				
				// r�cup�ration de tous les elements
				Vector<Qrel> listeAllElement = qrelReader.parseQrel(queryCurrent.getIdQuery());

				for (Qrel qrelSearch : listeAllElement) {
					
					// On cherche le qrel correspondant � l'identifiant de la queries parser
					if (StringUtils.equalsIgnoreCase(qrelSearch.getIdQrel(), queryCurrent.getIdQuery())) {
						mapSelectedDoc.put(qrelSearch.getNomDocument(), qrelSearch);
				
						if (qrelSearch.isPertinent()) {
							QueryResult qRes = new QueryResult(qrelSearch.getNomDocument(), qrelSearch.getxPath(), true);
							
							// On stocke les requetes
							mapResultQuery.put(queryCurrent.getQueryValue(), qRes);
						}
					}
				}
							
				// recuperation des mots de la queries lematis�
				String exprQuerie = queryCurrent.getQueryValue();
				String[] termeQuerie = exprQuerie.split("\\s");
				String[] termeQuerieLemmatise = new String[termeQuerie.length];
				
				for (int i = 0; i <termeQuerie.length; i++)
				{
					termeQuerieLemmatise[i] = XMLUtils.lematiser(spList, termeQuerie[i]);	
				}
				
				
				
				for (Entry<String, QueryResult> entryQueryTest : mapResultQuery.entrySet()) {

					String value = entryQueryTest.getKey();
					QueryResult qr = entryQueryTest.getValue();
					Float score = 0.0f;
					String[] termeToTerm = value.split("\\s");
					for (int i = 0; i < termeToTerm.length; i++) {
						for (int index = 0; index < termeFromDoc.length; index++) {
							if (StringUtils.equals(XMLUtils.lematiser(spList, termeFromDoc[index]), XMLUtils.lematiser(spList, termeToTerm[i]))) {
								
								listResultat = searchInIndexMot.findDocumentIfExistTerm(XMLUtils.lematiser(spList, termeToTerm[i]), qr.getXpath(), qr.getNomDoc());
								
								for (ResultSearch res : listResultat) {
									score += new Float(res.getPoid()*poid);
								}
							}
						}
					}
					scoreMap.put(qr.getNomDoc(), score);	
				}
			}
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
}
